/**
 * Copyright (c) 2018-2023, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 *
 * Contains: 
 *
 * Change Logs:
 * Date           Author            Notes
 * 2023-07-25     Shiroko           Init
 */
#ifndef __DRIVERS_VIRTIO_DEVICES_VIRTIO_GPU_H__
#define __DRIVERS_VIRTIO_DEVICES_VIRTIO_GPU_H__

/*
 * Virtio GPU coordinating system is using top-left as origin.
 */

#define VIRTIO_GPU_QUEUE_CONTROL    0
#define VIRTIO_GPU_QUEUE_CURSOR     1

#define VIRTIO_GPU_FEATURE_VIRGL            (1<<0)  // VirGL 3D mode is supported
#define VIRTIO_GPU_FEATURE_EDID             (1<<1)  // EDID is supported
#define VIRTIO_GPU_FEATURE_RESOURCE_UUID    (1<<2)  // Assigning Resources UUID is supported
#define VIRTIO_GPU_FEATURE_RESOURCE_BLOB    (1<<3)  // Creating & Using size-based blob resources is supported
#define VIRTIO_GPU_FEATURE_CONTEXT_INIT     (1<<4)  // Multiple context type and sync-timelines is supported (with VirGL)

#define VIRTIO_GPU_EVENT_DISPLAY            (1<<0)  // Display configuration has changed.

struct VirtioGPUDeviceConfig
{
    NX_U32 events_read;     // signals pending events to driver, read-only
    NX_U32 events_clear;    // clear pending events, writing event bit to this.
    NX_U32 num_scanouts;
    NX_U32 num_capsets;
};
typedef struct VirtioGPUDeviceConfig                      VirtioGPUDeviceConfig;

enum VirtioGPUSHMId
{
    VIRTIO_GPU_SHM_ID_UNDEFINED    = 0,
    VIRTIO_GPU_SHM_ID_HOST_VISIBLE = 1
};
typedef enum VirtioGPUSHMId                               VirtioGPUSHMId;

/*
 * Virtio GPU control queue
 */

enum VirtioGPUControlType
{
    /* 2d commands */
    VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
    VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
    VIRTIO_GPU_CMD_RESOURCE_UNREF,
    VIRTIO_GPU_CMD_SET_SCANOUT,
    VIRTIO_GPU_CMD_RESOURCE_FLUSH,
    VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
    VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
    VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
    VIRTIO_GPU_CMD_GET_CAPSET_INFO,
    VIRTIO_GPU_CMD_GET_CAPSET,
    VIRTIO_GPU_CMD_GET_EDID,
    VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID,
    VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB,
    VIRTIO_GPU_CMD_SET_SCANOUT_BLOB,

    /* 3d commands */
    VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
    VIRTIO_GPU_CMD_CTX_DESTROY,
    VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
    VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
    VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
    VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
    VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
    VIRTIO_GPU_CMD_SUBMIT_3D,
    VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB,
    VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB,

    /* cursor commands */
    VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
    VIRTIO_GPU_CMD_MOVE_CURSOR,

    /* success responses */
    VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
    VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
    VIRTIO_GPU_RESP_OK_CAPSET_INFO,
    VIRTIO_GPU_RESP_OK_CAPSET,
    VIRTIO_GPU_RESP_OK_EDID,
    VIRTIO_GPU_RESP_OK_RESOURCE_UUID,
    VIRTIO_GPU_RESP_OK_MAP_INFO,

    /* error responses */
    VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
    VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
    VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
    VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
    VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
    VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
};
typedef enum VirtioGPUControlType                         VirtioGPUControlType;

#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
#define VIRTIO_GPU_FLAG_INFO_RING_IDX (1 << 1)

struct VirtioGPUControlHeader
{
    // specifies the type of the driver request (VIRTIO_GPU_CMD_*) or device response (VIRTIO_GPU_RESP_*).
    NX_U32 type;
    // request / response flags.
    NX_U32 flags;
    // Available with VIRTIO_GPU_FLAG_FENCE
    NX_U64 fence_id;
    // Rendering context (used in 3D mode only).
    NX_U32 ctx_id;
    // Available with VIRTIO_GPU_FEATURES_CONTEXT_INIT
    NX_U8  ring_idx;
    NX_U8  padding[3];
};
typedef struct VirtioGPUControlHeader                     VirtioGPUControlHeader;

/*
 * Virtio GPU control queue response payload structures
 */

struct VirtioGPURect
{
    NX_U32 x;
    NX_U32 y;
    NX_U32 width;
    NX_U32 height;
};
typedef struct VirtioGPURect                              VirtioGPURect;

enum VirtioGPUFormats
{
    VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1,
    VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2,
    VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3,
    VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4,

    VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67,
    VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68,

    VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121,
    VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134,
};
typedef enum VirtioGPUFormats                             VirtioGPUFormats;


// DISPLAY_INFO
#define VIRTIO_GPU_MAX_SCANOUTS 16
struct VirtioGPUDisplayInfo
{
    struct
    {
        VirtioGPURect rect;
        NX_U32        enabled;
        NX_U32        flags;
    } modes[VIRTIO_GPU_MAX_SCANOUTS];
};
typedef struct VirtioGPUDisplayInfo                       VirtioGPUDisplayInfo;

struct VirtioGPUResponseDisplayInfo
{
    VirtioGPUControlHeader header;
    VirtioGPUDisplayInfo   displayInfo;
};
typedef struct VirtioGPUResponseDisplayInfo               VirtioGPUResponseDisplayInfo;

// EDID
struct VirtioGPURequestEDID
{
    VirtioGPUControlHeader header;
    NX_U32                 scanout;
    NX_U32                 padding;
};
typedef struct VirtioGPURequestEDID                       VirtioGPURequestEDID;

struct VirtioGPUResponseEDID
{
    VirtioGPUControlHeader header;
    NX_U32                 size;
    NX_U32                 padding;
    NX_U8                  edid[1024];
};
typedef struct VirtioGPUResponseEDID                      VirtioGPUResponseEDID;

// RESOURCE_CREATE_2D
struct VirtioGPURequestCreate2D
{
    VirtioGPUControlHeader header;
    NX_U32                 resource_id;
    NX_U32                 format;
    NX_U32                 width;
    NX_U32                 height;
};
typedef struct VirtioGPURequestCreate2D                   VirtioGPURequestCreate2D;

// RESOURCE_UNREF
struct VirtioGPURequestUnref
{
    VirtioGPUControlHeader header;
    NX_U32                 resource_id;
    NX_U32                 padding;
};
typedef struct VirtioGPURequestUnref                      VirtioGPURequestUnref;

// SET_SCANOUT
struct VirtioGPURequestSetScanout
{
    VirtioGPUControlHeader header;
    VirtioGPURect          rect;
    NX_U32                 scanout_id;
    NX_U32                 resource_id;
};
typedef struct VirtioGPURequestSetScanout                 VirtioGPURequestSetScanout;

// RESOURCE_FLUSH
struct VirtioGPURequestResourceFlush
{
    VirtioGPUControlHeader header;
    VirtioGPURect          rect;
    NX_U32                 resource_id;
    NX_U32                 padding;
};
typedef struct VirtioGPURequestResourceFlush              VirtioGPURequestResourceFlush;

// TRANSFER_TO_HOST_2D
struct VirtioGPURequestTransferToHost2D
{
    VirtioGPUControlHeader header;
    VirtioGPURect          rect;
    NX_U64                 offset;
    NX_U32                 resource_id;
    NX_U32                 padding;
};
typedef struct VirtioGPURequestTransferToHost2D           VirtioGPURequestTransferToHost2D;

// RESOURCE_ATTACH_BACKING
struct VirtioGPURequestResourceAttachBackingEntry
{
    NX_U64 addr;
    NX_U32 length;
    NX_U32 padding;
};
typedef struct VirtioGPURequestResourceAttachBackingEntry VirtioGPURequestResourceAttachBackingEntry;

struct VirtioGPURequestResourceAttachBacking
{
    VirtioGPUControlHeader                     header;
    NX_U32                                     resource_id;
    NX_U32                                     nr_entries;
    VirtioGPURequestResourceAttachBackingEntry entries[];
};
typedef struct VirtioGPURequestResourceAttachBacking      VirtioGPURequestResourceAttachBacking;

// RESOURCE_DETACH_BACKING
struct VirtioGPURequestResourceDetachBacking
{
    VirtioGPUControlHeader header;
    NX_U32                 resource_id;
    NX_U32                 padding;
};
typedef struct VirtioGPURequestResourceDetachBacking      VirtioGPURequestResourceDetachBacking;

// GET_CAPSET_INFO
struct VirtioGPURequestGetCapsetInfo
{
    VirtioGPUControlHeader header;
    NX_U32                 capset_index;
    NX_U32                 padding;
};
typedef struct VirtioGPURequestGetCapsetInfo              VirtioGPURequestGetCapsetInfo;

#define VIRTIO_GPU_CAPSET_VIRGL 1
#define VIRTIO_GPU_CAPSET_VIRGL2 2
#define VIRTIO_GPU_CAPSET_GFXSTREAM 3
#define VIRTIO_GPU_CAPSET_VENUS 4
#define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5
struct VirtioGPUCapsetInfo
{
    NX_U32 capset_id;
    NX_U32 capset_max_version;
    NX_U32 capset_max_size;
    NX_U32 padding;
};
typedef struct VirtioGPUCapsetInfo                        VirtioGPUCapsetInfo;
struct VirtioGPUResponseCapsetInfo
{
    VirtioGPUControlHeader header;
    VirtioGPUCapsetInfo    capsetInfo;
};
typedef struct VirtioGPUResponseCapsetInfo                VirtioGPUResponseCapsetInfo;

// GET_CAPSET
struct VirtioGPURequestGetCapset
{
    VirtioGPUControlHeader header;
    NX_U32                 capset_id;
    NX_U32                 capset_version;
};
typedef struct VirtioGPURequestGetCapset                  VirtioGPURequestGetCapset;

struct VirtioGPUResponseCapset
{
    VirtioGPUControlHeader header;
    NX_U8                  capset_data[];
};
typedef struct VirtioGPUResponseCapset                    VirtioGPUResponseCapset;

// RESOURCE_ASSIGN_UUID
struct VirtioGPURequestResourceAssignUUID
{
    VirtioGPUControlHeader header;
    NX_U32                 resource_id;
    NX_U32                 padding;
};
typedef struct VirtioGPURequestResourceAssignUUID         VirtioGPURequestResourceAssignUUID;

struct VirtioGPUResponseResourceUUID
{
    VirtioGPUControlHeader header;
    NX_U8                  uuid[16];
};
typedef struct VirtioGPUResponseResourceUUID              VirtioGPUResponseResourceUUID;

// RESOURCE_CREATE_BLOB
#define VIRTIO_GPU_BLOB_MEM_GUEST             0x0001
#define VIRTIO_GPU_BLOB_MEM_HOST3D            0x0002
#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST      0x0003

#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE     0x0001
#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE    0x0002
#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004

struct VirtioGPURequestResourceCreateBLOB
{
    VirtioGPUControlHeader header;
    NX_U32                 resource_id;
    NX_U32                 blob_mem;
    NX_U32                 blob_flags;
    NX_U32                 nr_entries;
    NX_U64                 blob_id;
    NX_U64                 size;
};
typedef struct VirtioGPURequestResourceCreateBLOB         VirtioGPURequestResourceCreateBLOB;

// SET_SCANOUT_BLOB
struct VirtioGPURequestSetScanoutBLOB
{
    VirtioGPUControlHeader header;
    VirtioGPURect          rect;
    NX_U32                 scanout_id;
    NX_U32                 resource_id;
    NX_U32                 width;
    NX_U32                 height;
    NX_U32                 format;
    NX_U32                 padding;
    NX_U32                 strides[4];
    NX_U32                 offsets[4];
};
typedef struct VirtioGPURequestSetScanoutBLOB             VirtioGPURequestSetScanoutBLOB;

/*
 * Virtio GPU cursor queue
 */
struct VirtioGPUCursorPos
{
    NX_U32 scanout_id;
    NX_U32 x;
    NX_U32 y;
    NX_U32 padding;
};
typedef struct VirtioGPUCursorPos                         VirtioGPUCursorPos;

struct VirtioGPURequestUpdateCursor // Or MoveCursor
{
    VirtioGPUControlHeader header;
    VirtioGPUCursorPos     pos;
    NX_U32                 resource_id;
    NX_U32                 hot_x;
    NX_U32                 hot_y;
    NX_U32                 padding;
};
typedef struct VirtioGPURequestUpdateCursor               VirtioGPURequestUpdateCursor;

/*
 * Device specified extension
 */

struct VirtioGPUScanout
{
    int              id;
    VirtioGPURect    rect;
    NX_Bool          enabled;
    void             *framebuffer;
    NX_Size          framebufferValidSize;
    NX_U32           resourceId;
    void             *cursorFramebuffer;
    NX_U32           cursorResourceId;
    VirtioGPUFormats format;
};
typedef struct VirtioGPUScanout                           VirtioGPUScanout;

struct VirtioGPUDeviceExtension
{
    VirtioGPUDeviceConfig *deviceConfig;
    VirtioGPUScanout      scanouts[VIRTIO_GPU_MAX_SCANOUTS];
    int                   selectedScanout;
    NX_U32                availableResourceId; // Hope NX_U32 won't run out of
};
typedef struct VirtioGPUDeviceExtension                   VirtioGPUDeviceExtension;

/*
 * Public interface
 */
#define VIRTIO_GPU_CMD_SELECT_SCANOUT       0x100

#define VIRTIO_GPU_CMD_QUERY_DISPLAY_INFO   0x110
#define VIRTIO_GPU_CMD_QUERY_EDID           0x111
#define VIRTIO_GPU_CMD_QUERY_CAPSET_INFO    0x112
#define VIRTIO_GPU_CMD_QUERY_CAPSET         0x113

#define VIRTIO_GPU_CMD_FRAMEBUFFER_TRANSFER 0x120
#define VIRTIO_GPU_CMD_FRAMEBUFFER_FLUSH    0x121

#define VIRTIO_GPU_CMD_CURSOR_UPDATE        0x130
#define VIRTIO_GPU_CMD_CURSOR_MOVE          0x131

#define VIRTIO_GPU_CMD_SETUP_SCANOUT        0x140

struct VirtioGPUControlArgument
{
    union
    {
        struct
        {
            int capsetId;
        }      queryCapsetInfo;
        struct
        {
            int capsetId;
            int capsetVer;
        }      queryCapset;
        NX_U32 fb_offset;
        struct
        {
            NX_U32 x;
            NX_U32 y;
            NX_U32 hotX;
            NX_U32 hotY;
            NX_U32 fb_offset;
        }      cursorUpdate;
        struct
        {
            NX_U32 x;
            NX_U32 y;
        }      cursorMove;
    }                arg;
    VirtioGPUFormats format;
    VirtioGPURect    rect;
    int              scanoutId;
    NX_Size          dataSize;
    void             *data;
};
typedef struct VirtioGPUControlArgument                   VirtioGPUControlArgument;


#endif // __DRIVERS_VIRTIO_DEVICES_VIRTIO_GPU_H__
